﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpActionModify.h"
#include "ActionModifyDefaultBehavior.h"

// ui Doc & View
#include "IUiDocument.h"
#include "UiViewUtils.h"
#include "IUiView.h"

// ui Frame

#include "IUiDocumentViewManager.h"

#include "IElementMoveContext.h"
#include "IElementTransformationComponent.h"
#include "ICommandManager.h"
#include "CommandParameters.h"
#include "IMenuItemContainerDefinition.h"

// Geometry
#include "Vector3dUtils.h"
#include "AlgorithmProject.h"
#include "IPlane.h"

// GBMP Db 
#include "ISelection.h" 
#include "IUserTransaction.h"
#include "IPureGraphicsElement.h" 
#include "IModelView.h" 
#include "IGraphicsNodeReference.h"
#include "IRegenerator.h"
#include "IReferencePlane.h"

// IElement
#include "IModelLine.h"
#include "IInstance.h"
#include "IElementStatus.h"
#include "IElementBasicInformation.h"

// Graphic
#include "IGraphicsPlane.h"
#include "IGraphicsLine.h"

// Snap  
#include "ISnap.h"
#include "ISnapCandidates.h"
#include "Snapper.h"
#include "UiSnapUtils.h"
#include "ISnapRender.h" 
#include "ISnapContext.h"
#include "ISnapSettings.h"
#include "IHighlights.h"

// Pick 
#include "IPick.h"
#include "IPickCandidates.h"
#include "IPickEventHandler.h"
#include "IPickTarget.h"
#include "IElementCanBePickedInModifyAction.h"
#include "IPickFilter.h"


// Join (迁移到Behavior）
#include "IModifyJoinRelationship.h"

// 罗盘显示
#include "ElementLocatorUtils.h"
#include "IElementLocator.h"


// 近程捕捉、远程捕捉建议添加接口
#include "GbmpDefaultPickFilterForLocalSnap.h"  
#include "GbmpDefaultPickFilterForRemoteSnap.h" 
#include "GbmpSnapEndPointPriorityTypesPreprocessor.h"


// 辅助对象夹点行为(需要Api完善)
#include "IElementShapeHandle.h"
#include "IGripPointsShapeHandleBehavior.h"
//////////////////////////////////////////////////////////////////////////

#include "IDrawingLayout.h"
#include "ILinkElementProxy.h"
#include "IMainWindow.h"

#include "ICommandInteractionEventArgs.h"
#include "IInteractionEventManager.h"

#include "ICombinedSnap.h"
#include "ICanvas.h"

#include "IHighlightChangeEventHandler.h"
#include "IHighlightChangeEventArgs.h"
#include "IHighlightChangeEvent.h"
#include "DebugMode.h"
#include "GcmpCommonDraw.h"
#include "GripUtil.h"
#include "IViewClipRange.h"
#include "IGenericElement.h"
#include "IDrawingTableItem.h"
#include "IDrawingTable.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IPreHighlights.h"
#include "GnufMainWindow.h"

#include "IDrawingTableUtils.h"
#include "IDrawingTableSelectionService.h"
#include "IUserCoordinateSystem.h"
#include "IUserCoordinateSystemStatusManager.h"

// 公共组件
#ifdef UiAdapter_IMPL
#include "GDFoundation/ElementSetsUtils.h"
#endif

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

namespace gcmp {
    class TestHighlightChangeEventHandler : public IHighlightChangeEventHandler//参考CanvasHighlightChangeEventHandler
    {
    public:
        TestHighlightChangeEventHandler() :m_isHighlightChanged(false) { }
        ~TestHighlightChangeEventHandler() { }

    public:
        bool IsHighlightChanged() const { return m_isHighlightChanged; }

        void ClearAllChanges() { m_isHighlightChanged = false; }

        void On(IHighlightChangeEventArgs* pArgs) override
        {
            const std::vector<const IGraphicsNodeReference*> refs = pArgs->GetGraphicsNodeReferences();
            HighlightChangedEventType eventType = pArgs->GetEventType();
            m_isHighlightChanged = true;
        }

    private:
        bool m_isHighlightChanged;
    };
}

using namespace gcmp;
CREATE_DEBUG_MODE(DisableAndDisplayLocator, L"禁用并显示罗盘", DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"禁用罗盘并显示时，鼠标抬起便会刷新视图，使禁用失效，需在录制日志时保持禁用状态");
CREATE_DEBUG_MODE(CollinearSnap, L"开启共线捕捉", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"希望开启共线捕捉，可以打开此开关！");
CREATE_DEBUG_MODE(HighlightChangedEventCallback, L"开启高亮变化事件回调", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"高亮变化事件回调");
EXPOSE_DEBUG_MODE_EXPORT(TransientWorkPlane, GCMP_COMMON_DRAW_EXPORT);
EXPOSE_DEBUG_MODE(PickGNodeRefsFiltered)
CREATE_DEBUG_MODE(OnlyPickMeshTriangle, L"仅允许拾取Mesh", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"仅允许拾取Mesh");
CREATE_DEBUG_MODE(OnlyPickRichText, L"仅允许拾取富文本", DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"仅允许拾取富文本");
CREATE_DEBUG_MODE(DisablePickGrep, L"不允许拾取整个Grep", DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"不允许拾取整个Grep");

namespace
{
    // 计算默认工作平面为捕捉平面
    void ComputeSnapContext(ISnapContext* snapContext, IUiView* pUiView)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiView, L"无效参数pUiView",L"GDMPLab",L"2024-03-30");

        IUiDocument* uiDoc = pUiView->GetUiDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(uiDoc, L"空指针uiDoc",L"GDMPLab",L"2024-03-30");
        IDocument* pDoc = uiDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"空指针pDoc",L"GDMPLab",L"2024-03-30");
        snapContext->SetDocument(pDoc);
        snapContext->SetViewerContext(pUiView->GetViewerContext());

        // 设置捕捉平面
        if (DEBUG_MODE(TransientWorkPlane))
        {
            IModelView* pModelView = pUiView->GetModelView();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"空指针pModelView",L"GDMPLab",L"2024-03-30");
            OwnerPtr<IPlane> opPlane = pModelView->GetWorkPlane();
            OwnerPtr<IGraphicsPlane> opGPlane = IGraphicsPlane::CreateByDirections(Vector3d(0, 0, 3000), opPlane->GetDirectionU(), opPlane->GetDirectionV());
            DBG_WARN_AND_RETURN_VOID_UNLESS(opGPlane, L"获取工作平面失败",L"GDMPLab",L"2024-03-30");
            snapContext->SetSnapPlane(*(opGPlane));
        }
        else if (DEBUG_MODE_SLOW(UserCoordinateSystemWorkPlane))
        {
            IModelView* pModelView = pUiView->GetModelView();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"空指针pModelView",L"GDMPLab",L"2024-03-30");
            if (pModelView->GetViewType() == BuiltInViewType::ThreeDimensional)
            {
                IUserCoordinateSystem* pUCS = IUserCoordinateSystemStatusManager::GetActivateUserCoordinateSystem(pDoc);
                OwnerPtr<IGraphicsPlane> opGPlane;
                if (pUCS != nullptr)
                {
                    opGPlane = IGraphicsPlane::CreateByDirections(pUCS->GetCoordinate().Origin(), pUCS->GetCoordinate().GetX(), pUCS->GetCoordinate().GetY());
                    DBG_WARN_AND_RETURN_VOID_UNLESS(opGPlane, L"获取工作平面失败",L"GDMPLab",L"2024-03-30");
                }
                else
                {
                    opGPlane = IGraphicsPlane::CreateByDirections(Vector3d(0, 0, 0), Vector3d(1, 0, 0), Vector3d(0, 1, 0));
                    DBG_WARN_AND_RETURN_VOID_UNLESS(opGPlane, L"获取工作平面失败",L"GDMPLab",L"2024-03-30");
                }
                snapContext->SetSnapPlane(*(opGPlane));
            } 
        }
        else
        {
            IModelView* modelView = pUiView->GetModelView();
            DBG_WARN_AND_RETURN_VOID_UNLESS(modelView, L"空指针modelView",L"GDMPLab",L"2024-03-30");
            OwnerPtr<IPlane> opPlane = modelView->GetWorkPlane();
            if (opPlane)
            {
                OwnerPtr<IGraphicsPlane> opGPlane = IGraphicsPlane::CreateByDirections(opPlane->GetOrigin(), opPlane->GetDirectionU(), opPlane->GetDirectionV());
                DBG_WARN_AND_RETURN_VOID_UNLESS(opGPlane, L"获取工作平面失败",L"GDMPLab",L"2024-03-30");
                snapContext->SetSnapPlane(*(opGPlane));
            }
        }
        
    }

    // 显示更新罗盘
    bool DisplayElementLocator(gcmp::IDocument * pDoc, const gcmp::IUiView * pCurrentView, bool isUpdatePos = true)
    {
        if (!ElementLocatorUtils::GetElementLocatorDisplayStatus())
        {
            return true;
        }
        DBG_WARN_AND_RETURN_UNLESS(pDoc, false, L"pDoc无效",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(pCurrentView, false, L"pCurrentView无效",L"GDMPLab",L"2024-03-30");

        std::set<ElementId> elemIds;
        const GraphicsNodeReferenceOwnerPtrSet& gnodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
        FOR_EACH(gnodeRef, gnodeRefs)
        {
            elemIds.insert(gnodeRef->GetElementId());
        }
        if (elemIds.empty())
        {
            return true;
        }

        if (!isUpdatePos)
        {
            IElementLocator *pLocator = IElementLocator::Get(pDoc);
            DBG_WARN_AND_RETURN_UNLESS(pLocator, false, L"pLocator无效",L"GDMPLab",L"2024-03-30");
            ElementLocatorUtils::UpdateElementLocatorByModelView(pCurrentView->GetModelView(), pLocator);
            ElementLocatorUtils::DisplayElementLocatorHandles(pLocator);
            return true;
        }

        if (!elemIds.empty())
        {
            IModelView* pModelView = pCurrentView->GetModelView();
            DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, false, L"ModelView无效",L"GDMPLab",L"2024-03-30");
            ElementLocatorUtils::DisplayElementLocator(pDoc, pModelView, elemIds);
            return true;
        }

        return false;
    }
    std::vector<OwnerPtr<ICurve3d>> GetElementComponentCurve(const IDocument* currenDoc, const IUiView* pCurrentView, const std::vector<gcmp::ElementId>& moveElementIds)
    {
        std::vector<OwnerPtr<ICurve3d>> snappableCurve;
        std::vector<OwnerPtr<IGeometry>> snappableGeometry;
        DBG_WARN_AND_RETURN_UNLESS(currenDoc, snappableCurve, L"空指针currenDoc",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(pCurrentView, snappableCurve, L"空指针pCurrentView",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(moveElementIds.size() > 0, snappableCurve, L"!moveElementIds.size() > 0",L"GDMPLab",L"2024-03-30");
        ElementId elementId = moveElementIds[0];
        DBG_WARN_AND_RETURN_UNLESS(elementId.IsValid(), snappableCurve, L"!elementId.IsValid()",L"GDMPLab",L"2024-03-30");
        const IElement* pElement = currenDoc->GetElement(elementId);
        DBG_WARN_AND_RETURN_UNLESS(pElement, snappableCurve, L"空指针pElement",L"GDMPLab",L"2024-03-30");
        IModelView* pModelView = pCurrentView->GetModelView();
        DBG_WARN_AND_RETURN_UNLESS(pModelView, snappableCurve, L"空指针pModelView",L"GDMPLab",L"2024-03-30");
        
        if (!snappableGeometry.empty())
        {
            FOR_EACH(opGeometry, snappableGeometry)
            {
                snappableCurve.emplace_back(TransferOwnershipCast<ICurve3d>(opGeometry));
            }
        }
        
        return snappableCurve;
    }

}

//////////////////////////////////////////////////////////////////////////
class ModifyActionPickFilter : public IPickFilter
{
public:
    ModifyActionPickFilter(gcmp::IDocument* pDocument);
    ~ModifyActionPickFilter(void);

    virtual bool AllowElement(const gcmp::ElementId& elementID) const override;
    virtual bool AllowGraphicsNode(const IGraphicsNodeReference& nodeReference) const override
    {
        return true;
    }
    virtual bool SetPickTargetOption(IPickTarget* pickTarget) override
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pickTarget, L"pickTarget is nullptr!",L"GDMPLab",L"2024-03-30");
        pickTarget->EnableGraphicsElementShape();
        if (DEBUG_MODE(PickGNodeRefsFiltered))
        {
            pickTarget->EnableAll();
            pickTarget->DisableEdge();
        }

        if (DEBUG_MODE(OnlyPickMeshTriangle))
        {
            pickTarget->DisableAll();
            pickTarget->EnableMeshTriangle();
        }

        if (DEBUG_MODE(OnlyPickRichText))
        {
            pickTarget->DisableAll();
            pickTarget->EnableText();
        }

        if (DEBUG_MODE(DisablePickGrep))
        {
            pickTarget->EnableAll();
            
            // 只为了添加接口覆盖
            pickTarget->DisableSegmentOfPolyCurve3d();
            pickTarget->EnableSegmentOfPolyCurve3d();

            pickTarget->DisableGraphicsElementShape();
        }
        
        return true;
    }
protected:
    const IDocument* GetDocument() const { return m_pDocument; }

private:
    const IDocument *m_pDocument;
};

ModifyActionPickFilter::ModifyActionPickFilter(gcmp::IDocument* pDocument)
    : m_pDocument(pDocument)
{
}
ModifyActionPickFilter::~ModifyActionPickFilter(void)
{
}
bool ModifyActionPickFilter::AllowElement(const gcmp::ElementId& elementId) const
{
    const IElementCanBePickedInModifyAction * pElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    if (pElementCanBePickedInModifyAction && pElementCanBePickedInModifyAction->IsEnabled())
    {
        const IDocument* pDoc = GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc不能为空",L"GDMPLab",L"2024-03-30");
        IElement *pElement = pDoc->GetElement(elementId);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"根据elementId获取的element指针为空，不合法",L"GDMPLab",L"2024-03-30");
        return pElementCanBePickedInModifyAction->CanBePicked(pElement);
    }
    return true;
}

/////////////////////////////////////////////////
GbmpActionModify::GbmpActionModify()
{
    m_startPt = m_endPt = m_interPt = m_nearStartPt = Vector3d(0, 0, 0);

    m_isCaught = false;
    m_status = PS_GBMP_NOTSTART;

    //只能选择针对Element的GRep
    m_pickTarget->EnableGraphicsElementShape();

    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr为空",L"GDMPLab",L"2024-03-30");
    IUiDocument* pCurrentUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentUiDoc, L"pCurrentUiDoc不能为空",L"GDMPLab",L"2024-03-30");

    m_opModifyElementsBehavior = NEW_AS_OWNER_PTR(ActionModifyDefaultBehavior);

    if (!gnuf::GnufMainWindow::bnufEnabled() && IMainWindow::GetMainWindow())
    {
        IMainWindow::GetMainWindow()->UpdateControlStatus();
    }

    // 默认捕捉设置
    IDocument*pDoc = pCurrentUiDoc->GetDbDocument();
    m_oFilterForLocalSnap = NEW_AS_OWNER_PTR(GbmpDefaultPickFilterForLocalSnap, pDoc, m_moveElementIds); // 近程捕捉
    m_oFilterForRemoteSnap = NEW_AS_OWNER_PTR(GbmpDefaultPickFilterForRemoteSnap, pDoc, m_moveElementIds);// 远程捕捉
}

GbmpActionModify::~GbmpActionModify()
{
    Reset();
}
void GbmpActionModify::SetModifyElementsBehavior(OwnerPtr<IActionModifyBehavior> opModifyBehavior)
{
    if (opModifyBehavior != nullptr)
        m_opModifyElementsBehavior = TransferOwnership(opModifyBehavior);
}
bool GbmpActionModify::AddPickPostProcessEventHandler(OwnerPtr<IPickEventHandler> opEventHandler)
{
    if (opEventHandler == nullptr)
        return false;

    m_opPickEventHandlers.emplace_back(TransferOwnership(opEventHandler));
    return AddPickPostProcessEvent(m_opPickEventHandlers.back().get());
}

bool GbmpActionModify::AddRectPickPostProcessEventHandler(OwnerPtr<IPickEventHandler> opEventHandler)
{
    if (opEventHandler == nullptr)
        return false;

    m_opRectPickEventHandlers.emplace_back(TransferOwnership(opEventHandler));
    return AddRectPickPostProcessEvent(m_opRectPickEventHandlers.back().get());
}

void GbmpActionModify::SetFilterForLocalSnap(OwnerPtr<gcmp::IPickFilter> oFilterForLocalSnap)
{
    if (oFilterForLocalSnap != nullptr)
        m_oFilterForLocalSnap = TransferOwnership(oFilterForLocalSnap);
}

void GbmpActionModify::SetFilterForRemoteSnap(OwnerPtr<gcmp::IPickFilter>  oFilterForRemoteSnap)
{
    if (oFilterForRemoteSnap != nullptr)
        m_oFilterForRemoteSnap = TransferOwnership(oFilterForRemoteSnap);
}



OwnerPtr<IMenuItemContainerDefinition> GbmpActionModify::PrepareContextMenu(IUiView* pUIView)
{
    ActionFinishReason childActionCancelReason = GetChildFinishReson();
    if (childActionCancelReason == ActionFinishReason::RButtonDown ||
        childActionCancelReason == ActionFinishReason::RButtonUp)
    {
        //子操作如果是右键结束，不需要弹右键菜单
        //清除子操作的状态，结束当前action
        KillMe();
        return nullptr;
    }

    OwnerPtr<IMenuItemContainerDefinition> opContextMenu;
    if (m_opModifyElementsBehavior)
    {
        opContextMenu = m_opModifyElementsBehavior->PrepareContextMenu(pUIView);
    }

    UpdateView();
    return opContextMenu;
}

void GbmpActionModify::InitAction(IUiView* pCurrentView)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"pCurrentView指针无效",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    m_upPickFilter = NEW_AS_OWNER_PTR(ModifyActionPickFilter, pDoc);
    GbmpPickActionBase::InitAction(pCurrentView);

    if (DEBUG_MODE(HighlightChangedEventCallback))
    {
        if (pDoc)
        {
            IHighlights *pHighlights = IHighlights::Get();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pHighlights, L"pHighlights为空",L"GDMPLab",L"2024-03-30");
            IHighlightChangeEvent *pHighlightsChangeEvent = pHighlights->GetHighlightChangeEvent();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pHighlightsChangeEvent, L"pHighlightChangeEvent为空",L"GDMPLab",L"2024-03-30");
            m_opHightlightChangeEventHandler = NEW_AS_OWNER_PTR(TestHighlightChangeEventHandler);
            pHighlightsChangeEvent->Add(m_opHightlightChangeEventHandler.get());
        }
    }
}

bool gcmp::GbmpActionModify::OnRButtonDown(IUiView * pCurrentView, const Vector3d & pos)
{
    return true;
}

bool gcmp::GbmpActionModify::OnRButtonUp(IUiView * pCurrentView, const Vector3d & pos)
{
    ActionFinishReason childActionCancelReason = GetChildFinishReson();
    if (childActionCancelReason == ActionFinishReason::RButtonDown ||
        childActionCancelReason == ActionFinishReason::RButtonUp)
    {
        return false;
    }

    IDocument *pDoc = pCurrentView->GetUiDocument()->GetDbDocument();
    //如果在鼠标右建释放时，Selection中已经选择了表格相关对象，则右建不在替换选择集
    {
        const std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>>& selectionGNodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
        FOR_EACH(iter, selectionGNodeRefs)
        {
            if (!iter)
            {
                continue;
            }
            ElementId id = iter->GetElementId();
            IElement* pElement = pDoc->GetElement(id);
            if (!pElement)
            {
                continue;
            }
            IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
            if (!pBasicInformation)
            {
                continue;
            }
            if (pBasicInformation->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT)
            {
                OnSelectionChanged();

                return true;
            }
        }
    }
    const gcmp::GraphicsNodeReferenceOwnerPtrVector& pickCandidate = IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences();
    if (1 == pickCandidate.size())
    {
        //在多选模型的状态下，再次右键选择其中一个模型，弹出右键菜单，此时不希望清除多模型中其他模型的选中状态.
        //AddToSelection会清除原有选择集，添加新的选择集，因此如果是多选模型的状态，不做处理，保持原有的选择集状态即可。
        bool isElementAlreadyInSelection = IsElementAlreadyInSelection(pickCandidate[0].get());
        if (!isElementAlreadyInSelection)
        {
            IElement* pElement = pDoc->GetElement((*pickCandidate.at(0)).GetElementId());
            IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);
            if (!pShapeHandle &&
                !ElementLocatorUtils::IsElementLocatorMovementHandler(pDoc, (*pickCandidate.at(0)).GetElementId()) &&
                !ElementLocatorUtils::IsElementLocatorRotationHandler(pDoc, (*pickCandidate.at(0)).GetElementId()) &&
                !ElementLocatorUtils::IsElementLocatorPlanarMoveHandler(pDoc, (*pickCandidate.at(0)).GetElementId()))
            {
                AddToSelection(pDoc, *pickCandidate.at(0), pCurrentView);
            }
        }
        else
        {
            //已经在选择集中，所以不加入，但必须清除掉
            IPickCandidates::Get()->DeletePick(IPickCandidates::Get()->GetCurrentPickIndex());
        }
    }
    else if (pickCandidate.size() > 1)
    {
        AddToSelectionGroup(pDoc, OwnerPtrContainerUtil::TransformVectorToSet(pickCandidate));
    }

    OnSelectionChanged();

    return true;
}


bool GbmpActionModify::OnLButtonDown(IUiView* pCurrentView, const Vector3d& pos)
{
    //基类的鼠标左边点击动作可以选择到辅助对象，但是在基类中此动作并不合法，在修改动作中才合法
    GbmpPickActionBase::OnLButtonDown(pCurrentView, pos);
    //计算与工作平面的交点，并返回所获得的点
    //先算一遍捕捉功能
    Vector3d posOnWP;
    IDocument*pDoc = pCurrentView->GetUiDocument()->GetDbDocument();
    // 准备移动的对象
    CollectMoveElements(pDoc);
    if (ActionBase::ProjectPositionOnWorkPlane(pCurrentView, pos, posOnWP))
    {
        if (m_auxElementId != ElementId::InvalidID)
        {
            // 此处的对象可能IElementShapeHandle或AuxiliaryElement
            if (const IElementShapeHandle *pShapeHandle = quick_cast<IElementShapeHandle>(pDoc->GetElement(m_auxElementId)))
            {
                //如果捕获的是裁剪框的夹点，则将pos加上折叠宽度
                const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pDoc->GetElement(pShapeHandle->GetMasterId()));
                if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
                {
                    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                    posOnWP = pCurrentView->GetCanvas()->MapFromSubView(posOnWP);
                }
            }
        }
        else if (m_moveElementIds.size() > 0)
        {
            gcmp::ElementId oElementId = m_moveElementIds[0];
            const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pDoc->GetElement(oElementId));
            if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
            {
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                posOnWP = pCurrentView->GetCanvas()->MapFromSubView(posOnWP);
            }
        }
        m_startPt = m_endPt = m_interPt = posOnWP;
    }

    if (HandledByOtherAction(pDoc, pos))
    {
        Reset();
        ICanvas *pCanvas = pCurrentView->GetCanvas();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
        pCanvas->Refresh();
        UpdateCandidates(pCurrentView, pos);

        UpdateView();
        return true;
    }

    m_oSnapContext = ISnapContext::Create();
    //保存最近的点，捕捉时有用
    GetNearestPoint(pCurrentView, m_startPt, m_nearStartPt);

    GbmpDefaultPickFilterForLocalSnap* pDefaultPickFilterForLocalSnap = dynamic_cast<GbmpDefaultPickFilterForLocalSnap*>(m_oFilterForLocalSnap.get());
    if (pDefaultPickFilterForLocalSnap)
        pDefaultPickFilterForLocalSnap->SetExcludedElementIds(m_moveElementIds);
    GbmpDefaultPickFilterForRemoteSnap* pDefaultPickFilterForRemoteSnap = dynamic_cast<GbmpDefaultPickFilterForRemoteSnap*>(m_oFilterForRemoteSnap.get());
    if (pDefaultPickFilterForRemoteSnap)
        pDefaultPickFilterForRemoteSnap->SetExcludedElementIds(m_moveElementIds);

    m_oSnapContext->SetInputPoint(pos);
    bool initSnapContext = UiSnapUtils::InitSnapContextFromUiView(m_oSnapContext.get(), pCurrentView, PickPointExchangeData::SnapPlaneType::WorkPlane);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(initSnapContext, L"初始化捕捉信息失败",L"GDMPLab",L"2024-03-30");
    m_oSnapContext->SetFilterForLocalSnap(GetFilterForLocalSnap());
    m_oSnapContext->SetFilterForRemoteSnap(GetFilterForRemoteSnap());

    if (m_auxElementId.IsValid())
    {
        IElement* pElement = pDoc->GetElement(m_auxElementId);
        std::vector<Int64> priorityTypes;
        if (IElementShapeHandle* pElementShapeHandle = quick_cast<IElementShapeHandle>(pElement))
        {
            const IElementShapeHandleBehavior* pBehavior = pElementShapeHandle->GetElementShapeHandleBehavior();
            const IGripPointsShapeHandleBehavior* pGripPointsShapeHandleBehavior = quick_cast<IGripPointsShapeHandleBehavior>(pBehavior);
            if (pGripPointsShapeHandleBehavior)
                priorityTypes = pGripPointsShapeHandleBehavior->GetSnapPriorityTypes();
        }

        if (priorityTypes.size() > 0)
        {
            SetSnapCandidatesPreprocessor(NEW_AS_OWNER_PTR(GbmpSnapEndPointPriorityTypesPreprocessor, priorityTypes));

            m_oSnapContext->SetSnapCandidatesPreprocessor(GetSnapCandidatesPreprocessor());
        }
    }
    else
    {
        OwnerPtr<ISnapSettings> settings = m_oSnapContext->GetSnapSettings();
        settings->SetIsRemoteSnapOff(true);
        settings->DisableAllSnaps();
        settings->SetCanSnapOriginalLine(true);
        m_oSnapContext->SetSnapSettings(settings.get());
    }

    m_oSnapContext->SetDataFromMovingElements(m_moveElementIds, m_nearStartPt);
    DisplayElementLocator(pDoc, pCurrentView, false);
    ICanvas *pCanvas = pCurrentView->GetCanvas();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
    pCanvas->Refresh();
    return true;
}

void GbmpActionModify::Reset()
{
    m_startPt = m_endPt = m_interPt = m_nearStartPt = Vector3d(0, 0, 0);

    m_isCaught = false;
    m_status = PS_GBMP_NOTSTART;

    m_moveElementIds.clear();

    ClearShadows();

    //捕捉结束
    ISnapRender::Get()->ClearSnapRenderData();
}

bool GbmpActionModify::OnLButtonDoubleClick(IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    GbmpPickActionBase::OnLButtonDoubleClick(pCurrentView, pos);

    const GraphicsNodeReferenceOwnerPtrSet& gnodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
    if (gnodeRefs.empty())
    {
        return true;
    }

    //表格单元格双击时，NodeRef不止一个，需要做特殊处理
    IDrawingTable* pTableElement = nullptr;
    if (gnodeRefs.size() > 1)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView, L"pCurrentView指针无效",L"GDMPLab",L"2024-03-30");
        IModelView* pModelView = pCurrentView->GetModelView();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
        ElementId gNodeElementId = (*gnodeRefs.begin())->GetElementId();
        IDocument* pDocument = pModelView->GetDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDocument, L"pDocument为空",L"GDMPLab",L"2024-03-30");
        IElement* pElement = pDocument->GetElement(gNodeElementId);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
        if(pGenericElement)
            pTableElement = quick_cast<IDrawingTable>(pGenericElement->GetExternalObject());
    }

    if (gnodeRefs.size() == 1 || (gnodeRefs.size() > 1 && pTableElement))
    {
        if (m_opModifyElementsBehavior)
        {
            bool res = m_opModifyElementsBehavior->OnLButtonDoubleClick(pCurrentView, pos, (*gnodeRefs.begin())->GetElementId());
            if (false == res)
            {
                return res;
            }
        }

        Reset();
        UpdateView();
    }
    return true;
}

namespace 
{
    std::set<TableItemIndex> g_otherPageIndexs;

    void RecordItemIndex(IDocument* pDocument)
    {
        g_otherPageIndexs.clear();
        if (!pDocument)
            return;
        ISelection* pSelection = ISelection::Get();
        if (pSelection)
        {
            const auto& oldSetSelectionDatas = pSelection->GetGraphicsNodeReferences();
            if (!(*oldSetSelectionDatas.begin()))
                return;
            ElementId tableId = (*oldSetSelectionDatas.begin())->GetElementId();
            IElement* pElement = pDocument->GetElement(tableId);
            if (!pElement)
                return;
            IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
            if (!pBasicInformation)
                return;
            IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
            if (!pGenericElement)
                return;
            const IDrawingTable* pDrawingTable = quick_cast<IDrawingTable>(pGenericElement->GetExternalObject());
            if (!pDrawingTable)
                return;

            FOR_EACH(itData, oldSetSelectionDatas)
            {
                if (!itData)
                    continue;
                ElementId id = itData->GetElementId();
                IElement* pElement = pDocument->GetElement(id);
                if (!pElement)
                    continue;
                IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
                if (!pBasicInformation)
                    continue;
                IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
                if (!pGenericElement)
                    continue;

                const IDrawingTableItem* pDrawingTableItem = quick_cast<IDrawingTableItem>(pGenericElement->GetExternalObject());
                if (pDrawingTableItem)
                {
                    if (pDrawingTableItem->GetDrawingTableElementId() == tableId)
                    {
                        TableItemIndex tempIndex = pDrawingTable->GetItemIndexByElementId(id);
                        if (pDrawingTableItem->IsHeader() && tempIndex.m_nPage > 0)
                        {
                            g_otherPageIndexs.insert(tempIndex);
                        }
                    }
                }
            }
        }
    }

    bool UpdateItemIndex(IDocument* pDocument, std::vector<OwnerPtr<IGraphicsNodeReference>>& oldDatas, std::set<TableItemIndex>& otherPageIndexs)
    {
        if (!pDocument || oldDatas.size() == 0)
            return false;
        IElement* pElement = pDocument->GetElement(oldDatas[0]->GetElementId());
        if (!pElement)
            return false;
        IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
        if (!pBasicInformation)
            return false;
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
        if (!pGenericElement)
            return false;
        const IDrawingTable* pDrawingTable = quick_cast<IDrawingTable>(pGenericElement->GetExternalObject());
        if (!pDrawingTable)
            return false;

        bool isInitId = false;
        ElementId currentId = ElementId::InvalidID;
        bool isUpdate = false;
        FOR_EACH(itData, oldDatas)
        {
            if (!itData)
                continue;
            ElementId id = itData->GetElementId();
            IElement* pElement = pDocument->GetElement(id);
            if (!pElement)
            {
                if (currentId != id)
                {
                    currentId = id;
                    if (isInitId)
                    {
                        otherPageIndexs.erase(otherPageIndexs.begin());
                    }
                    if (!isInitId)
                        isInitId = true;
                }
                const IDrawingTableItem* pItem = pDrawingTable->GetTableItem(*otherPageIndexs.begin());
                if (!pItem) 
                    continue;
                const IElement* pElement = pItem->GetOwnerElement();
                if (pElement) 
                {
                    itData->SetElementId(pElement->GetElementId());
                    isUpdate = true;
                }     
            }
        }
        return isUpdate;
    }

    void UpdateSelcetionOrHeight(IDocument* pDoc)
    {
        std::set<TableItemIndex> otherPageIndexs = g_otherPageIndexs;
        IHighlights* pHighlights = IHighlights::Get();
        if (pHighlights)
        {
            const auto& oldHighlightDatas = pHighlights->GetGraphicsNodeReferences();
            std::vector<OwnerPtr<IGraphicsNodeReference>> newDatas;
            std::vector<gcmp::OwnerPtr<gcmp::IGraphicsNodeReference>> oldHighLightDatasNew;
            FOR_EACH(oldData, oldHighlightDatas)
            {
                oldHighLightDatasNew.emplace_back(TransferOwnership(oldData->Clone()));
            }
            std::sort(oldHighLightDatasNew.begin(), oldHighLightDatasNew.end(), [](const gcmp::OwnerPtr<gcmp::IGraphicsNodeReference>& node1, const gcmp::OwnerPtr<gcmp::IGraphicsNodeReference>& node2)
            { return node1->GetElementId() < node2->GetElementId(); });
            bool isUpdate = UpdateItemIndex(pDoc, oldHighLightDatasNew, g_otherPageIndexs);
            if (!oldHighLightDatasNew.empty() && isUpdate)
            {
                pHighlights->SetGraphicsNodeReferences(oldHighLightDatasNew);
            }
        }

        ISelection* pSelection = ISelection::Get();
        if (pSelection && (!otherPageIndexs.empty()))
        {
            const auto& oldSetSelectionDatas = pSelection->GetGraphicsNodeReferences();
            std::vector<OwnerPtr<IGraphicsNodeReference>> newDatas;
            std::vector<OwnerPtr<IGraphicsNodeReference>> oldSelectionDatas = OwnerPtrContainerUtil::TransformSetToVector(oldSetSelectionDatas);
            bool isUpdate = UpdateItemIndex(pDoc, oldSelectionDatas, otherPageIndexs);
            if (isUpdate) 
            {
                std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>> newSetDatas = OwnerPtrContainerUtil::TransformVectorToSet(oldSelectionDatas);
                pSelection->Clear(pDoc);
                pSelection->ReplaceGroupGraphicsNodeReference(pDoc, newSetDatas);
            } 
            else 
            {
                std::vector<OwnerPtr<IGraphicsNodeReference>> tempNewDatas;
                tempNewDatas.emplace_back(TransferOwnership(oldSelectionDatas[0]->Clone()));
                std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>> newSetDatas = OwnerPtrContainerUtil::TransformVectorToSet(tempNewDatas);
                pSelection->Clear(pDoc);
                pSelection->ReplaceGroupGraphicsNodeReference(pDoc, newSetDatas);
            }
        }
        g_otherPageIndexs.clear();
        otherPageIndexs.clear();
    }
}

bool GbmpActionModify::OnLButtonUp(IUiView* pCurrentView, const Vector3d& pos)
{
    GbmpPickActionBase::OnLButtonUp(pCurrentView, pos);
    DBG_WARN_AND_RETURN_UNLESS(m_opModifyElementsBehavior, false, L"ModifyElementsBehavior指针为空",L"GDMPLab",L"2024-03-30");
    IDocument*pDoc = pCurrentView->GetUiDocument()->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, true, L"Document指针无效",L"GDMPLab",L"2024-03-30");
    DisplayElementLocator(pDoc, pCurrentView);


    if (Vector3dUtils::Distance(m_startPt, m_endPt) > 1)//起始点很接近，说明没有动过。这个值"1"有待研究
    {
        //这种情况才会移动
        bool cleared = ClearShadows();
        if (cleared)
        {//说明之前都在移动影子对象，所以现在需要移动真正的对象
            if (m_upUserTransaction == nullptr)
            {
                m_upUserTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"移动"), false);
                DBG_WARN_AND_RETURN_UNLESS(m_upUserTransaction != nullptr, false, L"事务创建不成功",L"GDMPLab",L"2024-03-30");
            }
            m_upUserTransaction->Start();

            CollectMoveElements(pDoc);//真正修改的时候，辅助对象已经无效，所以放心取真正的对象吧！
            bool isOk = true;
            for (int loop = 0; loop < (int)m_moveElementIds.size(); ++loop)
            {
                isOk = m_opModifyElementsBehavior->ModifyElement(pCurrentView, m_moveElementIds[loop], m_startPt, m_endPt - (IsCaught() ? m_nearStartPt : m_startPt));
                if (!isOk)
                {
                    Reset();
                    break;
                }
            }
            if (isOk)
            {
                m_upUserTransaction->Commit();
            }
            else
            {
                m_upUserTransaction->Rollback();
                ISelection::Get()->Clear(pDoc);
                IHighlights::Get()->Clear();
                OnSelectionChanged();
            }

            if (m_moveElementIds.size() > 0)
            {//数据有改变才需要更新视图
                UpdateView();
            }
        }
        else //没有移动影子对象，那就是在移动临时对象或者在非阴影模式下移动
        {
            if (m_upUserTransaction != nullptr && m_upUserTransaction->IsStarted())
            {
                bool isMoveTableElement = false;
                if (m_opModifyElementsBehavior)
                {
                    // 如果是表格的ElementShapeHandler则在鼠标Up的时候触发夹点移动
                    FOR_EACH(moveElementId, m_moveElementIds)
                    {
                        IElement* pMoveElement = pDoc->GetElement(moveElementId);
                        if (IElementShapeHandle* pMoveShapeHandler = quick_cast<IElementShapeHandle>(pMoveElement))
                        {
                            ElementId masterId = pMoveShapeHandler->GetMasterId();
                            DBG_WARN_AND_RETURN_FALSE_UNLESS(masterId.IsValid(), L"masterId无效",L"GDMPLab",L"2024-03-30");
                            IElement* pMasterElement = pDoc->GetElement(masterId);
                            DBG_WARN_AND_RETURN_FALSE_UNLESS(pMasterElement, L"辅助对象不应该没有master对象",L"GDMPLab",L"2024-03-30");
                            IElementBasicInformation* pBasicInformation = pMasterElement->GetBasicInformation();
                            DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInformation, L"pBasicInformation为空",L"GDMPLab",L"2024-03-30");
                            if (pBasicInformation->GetClassficationUid() == GuidUtils::FromString(L"{EDBC1DCC-7BC6-4EE1-BD90-0880B2E3E5C8}"))
                            {
                                RecordItemIndex(pDoc);
                                m_opModifyElementsBehavior->ModifyGripPoint(pCurrentView, moveElementId, m_startPt, m_endPt - (IsCaught() ? m_nearStartPt : m_startPt));
                                if (!g_otherPageIndexs.empty()) 
                                {
                                    UpdateSelcetionOrHeight(pDoc);
                                }
                                CleanupTempGraphicsShape();
                                isMoveTableElement = true;
                            }
                        }
                    }

                    m_opModifyElementsBehavior->ProcessPostModify(pCurrentView, m_moveElementIds, m_oSnapCandidates.get());
                }
                m_upUserTransaction->Commit();
            }
        }
    }
    // 表格夹点拖拽完成后，有可能单元格的选择集会发生变化，需要刷新下单元格选择集
    if (m_moveElementIds.size() == 1)
    {
        IElement* pElement = pDoc->GetElement(m_moveElementIds[0]);
        if (IsA<IElementShapeHandle>(pElement))
        {
            const IElementShapeHandle *pShapeHandle = quick_cast<IElementShapeHandle>(pElement);
            DBG_WARN_AND_RETURN_UNLESS(pShapeHandle, false, L"pElement无效",L"GDMPLab",L"2024-03-30");
            ElementId masterId = pShapeHandle->GetMasterId();
            if(IDrawingTableUtils::IsPageGripPoint(pDoc, m_moveElementIds[0]))
                IDrawingTableSelectionService::RefreshSelection(pDoc, masterId);
        }

    }


    Reset();
    UpdateView();
    return true;
}

//如果有临时对象，那么移动的是临时对象；否则取选择集中的对象
void GbmpActionModify::CollectMoveElements(IDocument* pDoc)
{
    m_moveElementIds.clear();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"传入的文档为空",L"GDMPLab",L"2024-03-30");
    if (m_auxElementId.IsValid())
    {
        m_moveElementIds.push_back(m_auxElementId);
    }
    else
    {
        const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
        for (auto it = selectedElems.begin(); it != selectedElems.end(); ++it)
        {
            ElementId id = (*it)->GetElementId();
            const IElement* pElement = pDoc->GetElement(id);
            DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"通过ID在文档中获取对象为空",L"GDMPLab",L"2024-03-30");
            const IInstance* pInstance = quick_cast<IInstance>(pElement);
            if (pInstance && pInstance->GetSuperInstanceId().IsValid())
                continue;
            m_moveElementIds.push_back(id);
        }
    }
}

bool GbmpActionModify::OnMovePoint(IUiView* pCurrentView, const Vector3d& pos)
{
    GbmpPickActionBase::OnMovePoint(pCurrentView, pos);
    if ((m_status & PS_GBMP_LBUTTON_DOWN) &&
        IsDraggingAwaySelectedElementsEnabled(pCurrentView))
    {
        m_moveElementIds.clear();
    }

    if ((m_status & PS_GBMP_LBUTTON_DOWN) &&
        ISelection::Get()->GetCount() > 0 &&
        !IsKeyAndButtonPressed(VK_CONTROL) &&
        !IsKeyAndButtonPressed(VK_SHIFT) &&
        IsAllowedMove())
    {//移动所选中的对象

        // 表格特殊处理
        {
            // 如果在鼠标move之前，点选中的是表格相关对象则不移动表格
            if (!m_moveElementIds.empty())
            {
                IDocument* pDoc = GetDoc();
                if (pDoc)
                {
                    FOR_EACH(elementId, m_moveElementIds)
                    {
                        IElement* pElement = pDoc->GetElement(elementId);
                        if (!pElement)
                        {
                            continue;
                        }

                        if (IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation())
                        {
                            if (pBasicInformation->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT || pBasicInformation->GetClassficationUid() == GuidUtils::FromString(L"{EDBC1DCC-7BC6-4EE1-BD90-0880B2E3E5C8}"))
                            {
                                m_moveElementIds.clear();
                                ISelection::Get()->Clear(pDoc);
                                IHighlights::Get()->Clear();
                                IPreHighlights::Get()->Clear();
                                return true;
                            }

                        }
                    }
                }

            }
            
        }


     //获取捕捉点
        SnapPoint(pCurrentView, pos);
        return OnMovePoint(pCurrentView);
    }

    return true;
}

bool GbmpActionModify::OnMovePoint(IUiView* pCurrentView)
{
    DBG_WARN_AND_RETURN_UNLESS(m_opModifyElementsBehavior, false, L"ModifyElementsBehavior指针为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(pCurrentView, false, L"无效参数pCurrentView",L"GDMPLab",L"2024-03-30");
    IModelView* pModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, false, L"pModelView无效",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = GetDoc();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, false, L"空指针pDoc",L"GDMPLab",L"2024-03-30");

#ifdef UiAdapter_IMPL
    //当选中的是集合时禁止移动
    std::vector<gcmp::ElementId> lstElementSetsBySelect = gdmp::ElementSetsUtils::GetRelationElementSets(pDoc, m_moveElementIds);
    if (static_cast<int>(lstElementSetsBySelect.size()) > 0)
    {
        return true;
    }
#endif

    std::vector<ElementId> elemIds;
    const GraphicsNodeReferenceOwnerPtrSet& gnodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
    FOR_EACH(gnodeRef, gnodeRefs)
    {
        elemIds.push_back(gnodeRef->GetElementId());
    }
    if (elemIds == m_moveElementIds)
    {
        DisplayElementLocator(pDoc, pCurrentView);
    }
    int moveTolerancePixel = 10; // pixels
    double moveTolerance = UiViewUtility::ComputeWorldWidthFromPixel(pCurrentView, moveTolerancePixel);
    if (!IsMoving() && Vector3dUtils::Distance(m_endPt, m_startPt) > moveTolerance)
        m_status = m_status | PS_GBMP_LBUTTON_MOVING;

    if (!IsMoving())
        return true;

    // 临时方案：在立面视图有捕捉点的情况下将m_nearStartPt点转换的平面空间
    Vector3d nearStartPt = m_nearStartPt;
    if (IsCaught() && Vector3dUtils::IsPerpendicular(pModelView->GetViewDirection(), Vector3d::UnitZ))
    {
        OwnerPtr<IPlane> workPlane = pModelView->GetWorkPlane();
        DBG_WARN_AND_RETURN_UNLESS(workPlane, false, L"workPlane无效",L"GDMPLab",L"2024-03-30");
        Vector2d uvParameter;
        AlgorithmProject::Project(m_nearStartPt, workPlane.get(), uvParameter, nearStartPt);
    }

    //// 过滤掉表格Item对象
    for (auto& iter = m_moveElementIds.begin(); iter != m_moveElementIds.end();)
    {
        ElementId id = *iter;
        IElement* pElement = pDoc->GetElement(id);
        if (IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement))
        {
            if (IDrawingTableItem* pTableItem = quick_cast<IDrawingTableItem>(pGenericElement->GetExternalObject()))
            {
                iter = m_moveElementIds.erase(iter);
                continue;
            }
        }
        iter++;
    }

    //真正开始移动对象
    for (int loop = 0; loop < (int)m_moveElementIds.size(); ++loop)
    {
        const IElement* pElement = pDoc->GetElement(m_moveElementIds[loop]);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement != nullptr, L"选择集中的Element非法",L"GDMPLab",L"2024-03-30");

        //Element不允许编辑
        const IElementStatus* pStatus = pElement->GetStatus();
        DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
        if (!pStatus->IsModifiable())
        {
            std::wstring promptMsg = GBMP_TR(L"Element") + StringUtil::ToWString(pElement->GetBasicInformation()->GetElementId().AsInt64()) + GBMP_TR(L"不允许编辑");
            SetPromptMessage(promptMsg);
            continue;
        }

        bool isPermantElem = !pElement->GetBasicInformation()->GetIsTransient();
        if (isPermantElem)
        {
            IElement* pShadow = GetShadow(pCurrentView, pElement);
            if (pShadow)
            {
                OwnerPtr<IElementMoveContext> opContext
                    = IElementMoveContext::CreateElementMoveContext(pDoc, pShadow->GetElementId(), m_endPt - m_interPt);
                pShadow->GetElementTransformationComponent()->Translate(*opContext);
            }
            else
            {
                // 非阴影模式移动时，所有对象都移动自身，所以要直接修改真正的对象，必须要启动事务。
                if (m_upUserTransaction == nullptr)
                {
                    m_upUserTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"移动"), false);
                    DBG_WARN_AND_RETURN_UNLESS(m_upUserTransaction != nullptr, false, L"事务创建不成功",L"GDMPLab",L"2024-03-30");
                }
                const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pElement);
                if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
                {
                    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                    m_endPt = pCurrentView->GetCanvas()->MapFromSubView(m_endPt);
                }
                if (m_upUserTransaction->IsStarted())
                {
                    m_upUserTransaction->Rollback();
                }
                m_upUserTransaction->Start();

                ElementId moveElementId = m_moveElementIds[0];
                if (DEBUG_MODE(CollinearSnap) && m_auxElementId != moveElementId)
                {
                    const ISnap* pSnap = m_oSnapCandidates->GetCurrentSnap();
                    const ICombinedSnap* pCombinedSnap = dynamic_cast<const ICombinedSnap*>(pSnap);
                    if (pSnap && (pSnap->GetSnapType() == SnapType::Collinear || (pCombinedSnap && pCombinedSnap->HasSubType(SnapType::Collinear))))
                    {
                        m_opModifyElementsBehavior->ModifyElement(pCurrentView, pElement->GetElementId(), m_startPt, m_endPt - (IsCaught() ? nearStartPt : m_startPt) + m_collinearVec);
                    }
                    else
                        m_opModifyElementsBehavior->ModifyElement(pCurrentView, pElement->GetElementId(), m_startPt, m_endPt - (IsCaught() ? nearStartPt : m_startPt));
                }
                else
                    m_opModifyElementsBehavior->ModifyElement(pCurrentView, pElement->GetElementId(), m_startPt, m_endPt - (IsCaught() ? nearStartPt : m_startPt));
                pDoc->GetRegenerator()->RegenerateDocument();
            }
        }
        //在ElementShapeHandle完全替换AuxiliaryElement后，将去除AuxiliaryElement相关逻辑
        else if (IsA<IElementShapeHandle>(pElement))
        {
            const IElementShapeHandle *pShapeHandle = quick_cast<IElementShapeHandle>(pElement);
            DBG_WARN_AND_RETURN_UNLESS(pShapeHandle, false, L"pElement无效",L"GDMPLab",L"2024-03-30");
            if (!pShapeHandle->CanMasterElementToMove())
            {
                FYI(L"辅助对象" + StringUtil::ToWString(pElement->GetElementId().AsInt64()) + L"的Master对象没有编辑权限，不能通过辅助对象移动Master对象");
                return false;
            }
            const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pDoc->GetElement(pShapeHandle->GetMasterId()));
            if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
            {
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                m_endPt = pCurrentView->GetCanvas()->MapFromSubView(m_endPt);
            }

            //移动临时对象时，会直接修改真正的对象，所以要启动事务。
            if (m_upUserTransaction == nullptr)
            {
                m_upUserTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"移动"), false);
                if (nullptr == m_upUserTransaction)
                {
                    return false;
                }
            }
            if (m_upUserTransaction->IsStarted())
            {
                m_upUserTransaction->Rollback();
                //临时对象一般是跟着一般对象走的，当一般对象Rollback时，更新临时对象
                std::vector<ElementId> elementIds(1, pElement->GetElementId());
                pDoc->GetRegenerator()->ForceRegeneratingElements(elementIds);
            }

            m_upUserTransaction->Start();

            gcmp::Vector3d auxNearStartPoint = nearStartPt;
            if ((pShapeHandle && pShapeHandle->IsMoveAlongWorkplane()))
            {
                DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, false, L"pModelView无效",L"GDMPLab",L"2024-03-30");

                OwnerPtr<IPlane> workPlane = pModelView->GetWorkPlane();
                DBG_WARN_AND_RETURN_UNLESS(workPlane, false, L"workPlane无效",L"GDMPLab",L"2024-03-30");
                Vector2d uvParam;
                AlgorithmProject::Project(m_nearStartPt, workPlane.get(), uvParam, auxNearStartPoint);
            }

            Vector3d startPt = (IsCaught() ? auxNearStartPoint : m_startPt);
            gcmp::Vector3d moveDir = m_endPt - startPt;
            if (m_opModifyElementsBehavior)
            {
                ElementId masterId = pShapeHandle->GetMasterId();
                DBG_WARN_AND_RETURN_FALSE_UNLESS(masterId.IsValid(), L"masterId无效",L"GDMPLab",L"2024-03-30");
                IElement* pMasterElement = pDoc->GetElement(masterId);
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pMasterElement, L"辅助对象不应该没有master对象",L"GDMPLab",L"2024-03-30");
                IElementBasicInformation* pBasicInformation = pMasterElement->GetBasicInformation();
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInformation, L"pBasicInformation为空",L"GDMPLab",L"2024-03-30");
                if (pBasicInformation->GetClassficationUid() != GuidUtils::FromString(L"{EDBC1DCC-7BC6-4EE1-BD90-0880B2E3E5C8}"))
                {
                    m_opModifyElementsBehavior->ModifyGripPoint(pCurrentView, m_moveElementIds[loop], startPt, moveDir);
                }
                else
                {
                    // 1. 复制新的表格对象
                    // 2. 在夹点的DrawingTableBehavior里面修改新的表格行高或列宽；
                    // 3. 然后再获取修改后的表格和单元格对象的视图GRep；
                    // 4. 删除复制的对象。OnLButtonUp
                    OwnerPtr<IGraphicsElementShape> opTempGraphicsShape = TransferOwnership(IDrawingTableUtils::GetTableViewShapeAfterElementShapeHandleMove(pDoc, m_moveElementIds[loop], startPt, moveDir));
                    if (opTempGraphicsShape)
                    {
                        DrawTempGraphicsElementShape(TransferOwnership(opTempGraphicsShape));
                        ElementId tempId = GetTempElementId();
                        IElement* pTempElement = pDoc->GetElement(tempId);
                        if (IPureGraphicsElement* pPureElement = quick_cast<IPureGraphicsElement>(pTempElement))
                        {
                            pPureElement->SetModelViewId(pModelView->GetElementId());
                        }
                    }
                }
            }
            pDoc->GetRegenerator()->RegenerateDocument();
        }
        else
        {
            continue;
        }
    }
    if (m_moveElementIds.size() > 0)
    {//数据有改变才需要更新视图
     //移动前，先删除掉InstanceJoinBehavior
        const IModifyJoinRelationship *pModifyJoinRelationship = IModifyJoinRelationship::GetModifyJoinRelationship();
        if (pModifyJoinRelationship)
        {
            pModifyJoinRelationship->DeleteMoveElementJoins(dynamic_cast<IDocument*>(pDoc), m_moveElementIds.front());
        }

        IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pDoc->GetElement(pCurrentView->GetModelView()->GetViewClipRangeId()));
        DBG_WARN_AND_RETURN_UNLESS(pViewClipRange, false, L"pViewClipRange 返回空指针",L"GDMPLab",L"2024-03-30");
        if (pViewClipRange->MergeRegions())
        {
            GripUtil::UpdateGripPoint(pModelView, true);
            m_moveElementIds.clear();
        }

        UpdateView();
    }

    m_interPt = m_endPt;
    return true;
}

IElement* GbmpActionModify::GetShadow(gcmp::IUiView* pCurrentView, const IElement* pElement)
{
    if (pElement == nullptr)
    {
        return nullptr;
    }

    if (IsA<IElementShapeHandle>(pElement))
    {
        return nullptr;
    }

    if (IsA<IModelLine>(pElement))
    {
        return nullptr;
    }

    const IReferencePlane * pRefPlane = quick_cast<const IReferencePlane>(pElement);
    if (pRefPlane && pRefPlane->GetIsFixed())
    {
        return nullptr;
    }

    IDocument* pDoc = GetDoc();
    ElementToShadowMap::iterator it = m_elementShadows.find(pElement->GetElementId());
    if (it != m_elementShadows.end())
    {
        return pDoc->GetElement(it->second);
    }

    //TODO:Element接口中移除CreateShadow接口，待重构
    IElement* pShadow = m_opModifyElementsBehavior->CreateElementShadow(pCurrentView, pElement->GetElementId());
    if (pShadow != nullptr)
    {
        m_elementShadows.insert(std::make_pair(pElement->GetElementId(), pShadow->GetElementId()));
        return quick_cast<IElement>(pShadow);
    }

    return nullptr;
}

bool GbmpActionModify::ClearShadows()
{
    bool cleared = false;
    IDocument* pDoc = GetDoc();

    ElementToShadowMap::iterator it = m_elementShadows.begin();
    for (; it != m_elementShadows.end(); ++it)
    {
        cleared = true;
        pDoc->DeleteElement(it->second);
    }

    m_elementShadows.clear();
    return cleared;
}

void GbmpActionModify::SnapPoint(IUiView* pCurrentView, const Vector3d& pos)
{
    //计算与工作平面的交点，并返回所获得的点
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"空指针pCurrentView",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView->GetUiDocument(), L"空指针pCurrentView->GetUiDocument()",L"GDMPLab",L"2024-03-30");
    IDocument* currenDoc = pCurrentView->GetUiDocument()->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(currenDoc, L"空指针currenDoc",L"GDMPLab",L"2024-03-30");

    Vector3d posOnWorkPlane;
    ActionBase::ProjectPositionOnWorkPlane(pCurrentView, pos, posOnWorkPlane);

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_oSnapContext.get(), L"空指针m_oSnapContext.get()",L"GDMPLab",L"2024-03-30");
    ComputeSnapContext(m_oSnapContext.get(), pCurrentView);//需要更新视图
    m_oSnapContext->SetInputPoint(pos);
    
    ElementId moveElementId;
    if (!m_moveElementIds.empty())
        moveElementId = m_moveElementIds[0];
    if (DEBUG_MODE(CollinearSnap) && m_auxElementId != moveElementId && !m_moveElementIds.empty())
    {
        //设置开启共线捕捉
        OwnerPtr<ISnapSettings> opSnapSetting = m_oSnapContext->GetSnapSettings();
        DBG_WARN_AND_RETURN_VOID_UNLESS(opSnapSetting.get(), L"空指针opSnapSetting.get()",L"GDMPLab",L"2024-03-30");
        //打开共线捕捉
        opSnapSetting->SetIsRemoteSnapOff(false);
        opSnapSetting->SetCanCentersSnap(false);
        opSnapSetting->SetCanExtensionSnap(false);
        opSnapSetting->SetCanParallelSnap(false);
        opSnapSetting->SetCanPerpendicularSnap(false);
        opSnapSetting->SetCanSnapCollineation(true);
        m_oSnapContext->SetSnapSettings(opSnapSetting.get());

        if (!m_moveElementIds.empty())
        {
            std::vector<OwnerPtr<ICurve3d>> opCurve = GetElementComponentCurve(currenDoc, pCurrentView, m_moveElementIds);
            if (!opCurve.empty() && opCurve[0].get())
            {
                Vector3d orginalPoint = posOnWorkPlane - m_collinearVec;
                Vector3d dir = quick_cast<ILine3d>(opCurve[0].get())->GetDirection();
                dir.Normalize();
                const Intervald intervald = opCurve[0]->GetLimits();
                OwnerPtr<ILine3d> opCollinear = ILine3d::Create(orginalPoint, dir, intervald);
                OwnerPtr<ICurve3d> opCollinearCurve = TransferOwnershipCast<ICurve3d>(TransferOwnership(opCollinear));
                if (opCollinearCurve.get())
                    m_oSnapContext->SetCollinearCurve(opCollinearCurve.get());
            }
        }
    }

    m_oSnapCandidates = Snapper::Snap(m_oSnapContext.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_oSnapCandidates, L"空指针m_opSnapCandidates",L"GDMPLab",L"2024-03-30");
    const ISnap* snap = m_oSnapCandidates->GetCurrentSnap();
    if (snap)
    {
        m_endPt = snap->GetSnappedPoint();
        m_isCaught = true;
        SetPromptMessage(snap->GetLongPrompt());
    }
    else
    {
        m_endPt = posOnWorkPlane;
        m_isCaught = false;
        SetPromptMessage(L"");
    }

    ISnapRender::Get()->Draw(snap, SnapTextPositionType::LowerRight);

    UpdateView();
}

void GbmpActionModify::GetNearestPoint(IUiView* pCurrentView, const Vector3d& inputPoint, Vector3d& nearPoint)
{
    nearPoint = inputPoint;
    m_collinearVec = Vector3d();
    const IDocument* currenDoc = pCurrentView->GetUiDocument()->GetDbDocument();

    //辅助对象和真正的对象应该分开处理
    if (m_auxElementId.IsValid())
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_moveElementIds.size() == 1 && m_auxElementId == m_moveElementIds[0],L"辅助对象id不对",L"GDMPLab",L"2024-03-30");
        IElement* pElement = currenDoc->GetElement(m_auxElementId);
        IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);

        if (pShapeHandle != nullptr)
        {
            pShapeHandle->GetElementShapeHandleBehavior()->GetNearestPoint(nearPoint);
            const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(currenDoc->GetElement(pShapeHandle->GetMasterId()));
            if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
            {
                DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                nearPoint = pCurrentView->GetCanvas()->MapFromSubView(nearPoint);
            }
        }
    }
    else
    {
        IDocument* pDoc = GetDoc();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc不能为空",L"GDMPLab",L"2024-03-30");

        OwnerPtr<ISnapContext> opContext = ISnapContext::Create();
        DBG_WARN_AND_RETURN_VOID_UNLESS(opContext.get(), L"空指针opContext.get()",L"GDMPLab",L"2024-03-30");
        ComputeSnapContext(opContext.get(), pCurrentView);
        opContext->SetInputPoint(inputPoint);

        OwnerPtr<ISnapSettings> settings = opContext->GetSnapSettings();
        DBG_WARN_AND_RETURN_VOID_UNLESS(settings.get(), L"空指针settings.get()",L"GDMPLab",L"2024-03-30");
        settings->SetIsRemoteSnapOff(true);
        settings->DisableAllSnaps();
        settings->SetCanSnapNearest(true);
        opContext->SetSnapSettings(settings.get());

        OwnerPtr<ISnapCandidates> candidates = Snapper::Snap(opContext.get());
        DBG_WARN_AND_RETURN_VOID_UNLESS(candidates.get(), L"空指针candidates.get()",L"GDMPLab",L"2024-03-30");
        const ISnap* pSnap = candidates->GetCurrentSnap();
        if (pSnap)
        {
            nearPoint = pSnap->GetSnappedPoint();
            if (m_moveElementIds.size() > 0)
            {
                gcmp::ElementId oElementId = m_moveElementIds[0];
                const IViewClipRange* pViewClipRange = quick_cast<IViewClipRange>(pDoc->GetElement(oElementId));
                if (pViewClipRange && pViewClipRange->GetSplitType() != EnSplitType::Unknown)
                {
                    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView->GetCanvas(), L"canvas不能为空",L"GDMPLab",L"2024-03-30");
                    nearPoint = pCurrentView->GetCanvas()->MapFromSubView(nearPoint);
                }
            }
        }
        
        if (DEBUG_MODE(CollinearSnap))
        {
            if (m_moveElementIds.size() == 0)
                return;

            if (!m_moveElementIds.empty())
            {
                ElementId moveElementId = m_moveElementIds[0];
                if (m_auxElementId == moveElementId)
                    return;
                std::vector<OwnerPtr<ICurve3d>> opComponentCurve = GetElementComponentCurve(currenDoc, pCurrentView, m_moveElementIds);
                if (!opComponentCurve.empty())
                {
                    m_oSnapContext->SetCollinearCurve(opComponentCurve[0].get());
                }
                else
                    return;
                const ICurve3d* pSnapComponentCurve = m_oSnapContext->GetCollinearCurve();
                if (!pSnapComponentCurve)
                    return;
                double uvParameter;
                Vector3d projectedPoint;
                const ILine3d* snapLine = quick_cast<const ILine3d>(pSnapComponentCurve);
                if (!snapLine)
                    return;
                OwnerPtr<ICurve3d>  pGmICurve3d = AlgorithmProject::ProjectReturnCurve3d(pSnapComponentCurve, m_oSnapContext->GetSnapPlane().GetGmIPlane());
                if (!pGmICurve3d.get())
                    return;
                AlgorithmProject::Project(nearPoint, quick_cast<const ILine3d>(pGmICurve3d.get()), uvParameter, projectedPoint);
                m_collinearVec = nearPoint - projectedPoint;
            }
        }
    }

}

bool GbmpActionModify::HandledByOtherAction(IDocument*pDoc, const Vector3d& pos)
{
    if (m_moveElementIds.size() != 1)//暂时只处理一个的情况
    {
        return false;
    }

    if (IsKeyAndButtonPressed(VK_CONTROL) || IsKeyAndButtonPressed(VK_SHIFT))
    {
        //如果Shift/Ctrl被按下，则不会激活命令
        return false;
    }

    //暂时只处理辅助对象，以后如果需要的话，用通用的Element代替
    IElement* pElement = pDoc->GetElement(m_moveElementIds[0]);

    //////////////////////////////////////////////////////////////////////////
    // TODO：临时方案，请罗盘ShapeHandler对象Api完成后去掉
    std::wstring elemName = pElement->GetBasicInformation()->GetName();
    if (elemName == L"gmLocatorRotateCmd" || elemName == L"gmLocatorLinearMoveCmd"
        || elemName == L"gmLocatorOnlyRotateCmd" || elemName == L"gmLocatorMoveCmd"
        || elemName == L"gmLocatorPlanarMoveCmd" || elemName == L"gmLocatorPlanarMoveOnlyCmd")
    {
        IElementLocator* pLocator = IElementLocator::Get(pDoc);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLocator, L"pLocator为空",L"GDMPLab",L"2024-03-30");

        if (DEBUG_MODE(DisableAndDisplayLocator))
        {
            pLocator->DisableAllMovementAndRotation();
        }

        gcmp::CommandParameters cmdParams;
        cmdParams[L"ElementId"] = pElement->GetElementId().AsInt64();

        //新增参数只能放在最后面，否则影响其它操作逻辑
        cmdParams[L"Vector3d_X"] = pos.X();
        cmdParams[L"Vector3d_Y"] = pos.Y();
        cmdParams[L"Vector3d_Z"] = pos.Z();
        ICommandManager::Get()->SendCommand(elemName, cmdParams);
        return true;
    }
    //////////////////////////////////////////////////////////////////////////

    IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);

    IInstance* pInstance = quick_cast<IInstance>(pElement);
    if (pShapeHandle != nullptr)
    {
        std::wstring commandStr;
        gcmp::CommandParameters cmdParams;
        if (pShapeHandle && pShapeHandle->GetElementShapeHandleBehavior() && pShapeHandle->GetElementShapeHandleBehavior()->GetHandleCommandString(nullptr, commandStr, cmdParams))
        {
            //新增参数只能放在最后面，否则影响其它操作逻辑
            cmdParams[L"Vector3d_X"] = pos.X();
            cmdParams[L"Vector3d_Y"] = pos.Y();
            cmdParams[L"Vector3d_Z"] = pos.Z();
            ICommandManager::Get()->SendCommand(commandStr, cmdParams);
            return true;
        }
    }
    else if (pInstance != nullptr)
    {
        OwnerPtr<ICommandInteractionEventArgs> opArgs = ICommandInteractionEventArgs::Create(
            pInstance);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opArgs, L"opArgs为空",L"GDMPLab",L"2024-03-30");
        opArgs->SetClickType(ClickType::SingleClick);
        CommandParameters cmdParams;
        cmdParams[L"Vector3d_X"] = m_startPt.X();
        cmdParams[L"Vector3d_Y"] = m_startPt.Y();
        cmdParams[L"Vector3d_Z"] = m_startPt.Z();
        opArgs->SetCommandParameters(cmdParams);
        IInteractionEventManager* pMgr = IInteractionEventManager::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pMgr, L"pMgr为空",L"GDMPLab",L"2024-03-30");
        pMgr->Execute(opArgs.get());
        if (opArgs->IsExcuted())
        {
            return true;
        }
    }

    return false;
}


bool GbmpActionModify::IsMoving() const
{
    return (m_status & PS_GBMP_LBUTTON_MOVING) != 0;
}

bool GbmpActionModify::OnKeyDown(gcmp::IUiView* pCurrentView, int nChar)
{
    DBG_WARN_AND_RETURN_UNLESS(pCurrentView, false, L"无效参数pCurrentView",L"GDMPLab",L"2024-03-30");

    if (IsKeyAndButtonPressed(VK_CONTROL))
    {
        SetCursorType(CursorType::ArrowCursorWithPlus);
    }
    else if (IsKeyAndButtonPressed(VK_SHIFT))
    {
        SetCursorType(CursorType::ArrowCursorWithMinus);
    }

    if (GbmpPickActionBase::OnKeyDown(pCurrentView, nChar))
        return true;

    if (nChar == 9)
    {
        if (nullptr == m_oSnapCandidates)
            return false;
        const std::vector<const ISnap*>& snapResults = m_oSnapCandidates->GetCandidates();
        size_t numResults = snapResults.size();
        if (numResults > 1)
        {
            const ISnap* pSnap = m_oSnapCandidates->UpdateCurrentSnapToNext();
            DBG_WARN_AND_RETURN_UNLESS(pSnap, false, L"pSnap为空",L"GDMPLab",L"2024-03-30");

            m_isCaught = true;
            SetPromptMessage(pSnap->GetLongPrompt());
            m_endPt = pSnap->GetSnappedPoint();

            ISnapRender::Get()->Draw(pSnap, SnapTextPositionType::LowerRight);

            OnMovePoint(pCurrentView);
        }

        return true;
    }


    return false;
}

bool gcmp::GbmpActionModify::OnKeyUp(gcmp::IUiView* pCurrentView, int nChar)
{
    CursorType cursorType = GetCursorType();
    if (cursorType == CursorType::ArrowCursorWithPlus ||
        cursorType == CursorType::ArrowCursorWithMinus)
    {
        SetCursorType(CursorType::ArrowCursor);
    }

    return GbmpPickActionBase::OnKeyUp(pCurrentView, nChar);
}

void GbmpActionModify::ActionCancelled()
{
    GbmpPickActionBase::ActionCancelled();

    if (m_upUserTransaction != nullptr && m_upUserTransaction->IsStarted())
    {
        IDocument* pDoc = GetDoc();
        m_upUserTransaction->Rollback();
        ISelection::Get()->Clear(pDoc);
        IHighlights::Get()->Clear();
        OnSelectionChanged();
        IPickCandidates::Get()->Clear();
    }

    CleanupTempGraphicsShape();
    Reset();
    MarkFinishStatus(ActionFinishStatus::Cancelled);
}

bool GbmpActionModify::OnViewSwitched(gcmp::IUiView* pUIView)
{
    if (pUIView && pUIView->GetModelView())
    {
        IModelView* pModelView = pUIView->GetModelView();
    }
    return false;
}

void GbmpActionModify::OnSelectionChanged()
{
    GbmpPickActionBase::OnSelectionChanged();
    if (m_opModifyElementsBehavior)
    {
        IDocument* pDoc = GetDoc();
        m_opModifyElementsBehavior->OnSelectionChanged(pDoc);
    }
}

bool GbmpActionModify::IsElementAlreadyInSelection(const IGraphicsNodeReference* pGraphicsNodeReference)
{
    if (pGraphicsNodeReference == nullptr)
        return false;

    const std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>>& selectedItems = ISelection::Get()->GetGraphicsNodeReferences();

    for (auto iter = selectedItems.begin(); iter != selectedItems.end(); ++iter)
    {
        if ((*iter)->GetElementId() == pGraphicsNodeReference->GetElementId())
        {
            return true;
        }
    }

    return false;
}
